package cn.itsource.itsource.service.impl;

import cn.itsource.itsource.domain.User;
import cn.itsource.itsource.domain.Employee;
import cn.itsource.itsource.dto.LoginDto;
import cn.itsource.itsource.util.AjaxResult;
import cn.itsource.itsource.mapper.UserMapper;
import cn.itsource.itsource.dto.RegisterDto;
import cn.itsource.itsource.service.IUserService;
import cn.itsource.itsource.service.RedisService;
import cn.itsource.itsource.util.HttpUtil;
import cn.itsource.itsource.util.MD5;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.io.IOException;
import java.util.HashMap;
import java.util.UUID;

@Service
@Transactional //事务
public class UserServiceImpl implements IUserService {
    public static final Integer CODE_MINUTES = 5;
    public static final String SEND_MSG_PREFIX = "check_phone_one_minutes_exits";

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private RedisService redisService;


    @Override
    public AjaxResult login(LoginDto dto) {
        //TODO 2021年10月20日：代码改造：门户前端和运营前端的登录都统一走这个逻辑
        if (dto.getUserType() == null) {
            return AjaxResult.error("缺少必传参数");
        }

        //        6.验证通过后，创建一个token
        String token = StringUtils.replace(UUID.randomUUID().toString(), "-", "");

        Employee employee = null;
        User user = null;
        if (dto.getUserType().intValue() == LoginDto.USER_TYPE_QIANDUAN) {//门户前端登录
            //1. 验证登录帐号和密码（验证时，注意：密码是经过了加密，加密规则：md5(原密码+Salt)）
            //2. 先根据登录帐号查t_user信息，再根据查出来的user信息，判断密码，确定是否能登录成功
            Example example = new Example(User.class);
            example.and().andEqualTo("username", dto.getUsername());
            user = userMapper.selectOneByExample(example);//排除垃圾数据的问题，根据用户名，肯定是只能一条或0条数据
            if (user == null) {
                return AjaxResult.error("帐号或密码错误");
            }
            //3. 验证密码。加密规则：md5(原密码+Salt)）
            String secret_pass = MD5.getMD5(dto.getPassword() + user.getSalt());
            if (!StringUtils.equals(secret_pass, user.getPassword())) {
                return AjaxResult.error("密码错误");
            }

            //接下来，要生成token令牌，并根据token为key,用户信息为value保存到Redis
            redisService.setStringKeyAndValue(token, user, 30);
        } else {//运营前端登录
            //        4.后台执行登录操作
//        5.后台验证登录帐号和密码（到 员工表中查询用户信息）
            employee = userMapper.login(dto.getUsername(), dto.getPassword());
            if (employee == null) {
                return AjaxResult.error("帐号或密码错误");
            }

            //接下来，要生成token令牌，并根据token为key,emp信息为value保存到Redis
            //        7.将token作为key,用户的登录信息作为value，保存到redis
            //TODO 优化：当用户登录成功后，如果用户30分钟内不对系统进行任何操作，则系统 自动退出
            redisService.setStringKeyAndValue(token, employee, 30);
        }


//        8.将token返回给前端
        return AjaxResult.success("登录成功").setData(token);

    }

    @Override
    public void register(RegisterDto dto) {
        User user = new User();
        user.setUsername(dto.getPhone());
        user.setPhone(dto.getPhone());
        String salt = StringUtils.replace(UUID.randomUUID().toString(), "-", "");
        String md5 = MD5.getMD5(dto.getPassword() + salt);
        user.setPassword(md5);
        user.setSalt(salt);
        userMapper.register(user);
    }

    @Override
    public AjaxResult checkphone(String tel) {
        /*
            如何根据手机号判断是否重复？
                根据手机号去数据库t_user查询，如果能查到数据，则重复了，否则 可以用

            提示：因为这里不需要返回结果，只需要查看是否存在，所以在验证时的
            Sql:select count(1) from t_user where phone = ?

         */
        return AjaxResult.success("当前手机号可用");
    }



    @Override
    public AjaxResult sendMobileCode(String phone) {
        //TODO 验证技巧：在进行验证操作时，先将所有不满足条件的验证，全部判断完，如果所有 验证都通过了，则正确的操作！！！

        // 操作之前，还需要进行相关校验（手机号格式、手机号是否重复、短信发送的频率）
        //验证 ： 短信发送的频率：1分钟内，只发送一次；5分钟内，不再重复生成验证码

        //0.1 先根据手机号从redis取值
        String checkPhoneExists = redisService.getKeyObjectValue(SEND_MSG_PREFIX + phone, String.class);
        if (StringUtils.isNotBlank(checkPhoneExists)) {//不为空，不能再发了
            //不能再发，提示前端，1分钟内，同一手机号不能重复发送短信
            return AjaxResult.error("1分钟内，同一手机号不能重复发送短信");
        }

        // 0.2   5分钟内，不再重复生成验证码
        String code = redisService.getKeyObjectValue(phone, String.class);
        if (StringUtils.isBlank(code)){//如果为空，则再生成
            //1. 先生成一个随机的短信验证码（6位数字）
            code = RandomStringUtils.randomNumeric(6);
            //3. 将生成的验证和手机号，形成key-value，保存到redis
            redisService.setStringKeyAndValue(phone, code, CODE_MINUTES);
        }

        //2. 调用短信网关，发送短信:d41d8cd98f00b204e980

        System.out.println("发送的短信验证码是：" + code);


        //测试 post请求发送
        HashMap<String, String> map = new HashMap<>();
        map.put("Uid", "x286129277");
        map.put("Key", "d41d8cd98f00b204e980");
        map.put("smsMob", "13512345678");
        map.put("smsText", "x286192277");

        HttpUtil httpUtil=new HttpUtil("http://utf8.api.smschinese.cn",map);
        try {
            httpUtil.post();
        } catch (IOException e) {
            e.printStackTrace();
        }
        String json = httpUtil.getContent();

        System.out.println(json);


        //4. 如果成功发送，需要添加一个标识（值随便写）
        redisService.setStringKeyAndValue(SEND_MSG_PREFIX + phone, "flag", 1);


        return AjaxResult.success("发送成功");

    }


}
